using System;
using System.Collections.Generic;
using System.Text;
using SP.Parameter;

namespace SP.HwDeferredRS
{
    class DeferredVolumeFusion : AbstractFusion
    {
        public DeferredVolumeFusion()
        {
            // param sys_Illum
            AddParameter(
                new Texture2dParamter("sys_Depth", "sys_DepthSamp")
                .SetSRGBTexture(false)
                .SetEditable(false)
                .SetUserData("fragment")
                );

            // param baseMap
            AddParameter(
                new Texture2dParamter("volumeMap", "volumeMapSamp")
                .SetSRGBTexture(false)
                .SetUserData("fragment")
                .SetDesc("R: Alpha map, G: Original color blending map, B: unused, A: displacement map")
                );

            AddParameter(
                new ScalarParameter("volumeMaxDisplacement")
                .SetS(1)
                .SetDesc("Volume maximum displacement")
            );

            AddParameter(
                new ColorParameter("originColor")
                .SetR(1)
                .SetG(1)
                .SetB(1)
                .SetA(1)
                .SetDesc("The original color of the volume")
            );

            AddPreprocessor(new Preprocessor("VOLUMEMAP_UV", 1, 3, 1, "UV channel (1-3) for volumeMap."));
        }

        public override string Name
        {
            get { return "DeferredVolume"; }
        }

        public override string Desc
        {
            get { return ""; }
        }

        public override Stage Stage
        {
            get { return Stage.Override; }
        }

        public override int UVChannelCount
        {
            get { return GetPreprocessor("VOLUMEMAP_UV").Value; }
        }

        public override void Code(StringBuilder b, string platform)
        {
            // First, fetch the lightcone half depth from the texture
            // Before fetching the texture, perform parallax offest mapping...
            AddLine(b, "vec4 volMap = tex2D(volumeMapSamp, pipeline.Texcoord[VOLUMEMAP_UV-1]);");
            AddLine(b, "clip(volMap.ra - vec2(1e-3, 1e-3));");

            // pipeline.Albedo is set to cCustom0.rgb
            AddLine(b, "pipeline.FragColor = lerp(pipeline.Albedo, originColor.rgb, volMap.g);");
            AddLine(b, "float lightConeHalfDepth = volMap.a;");

            // The the gradient inside ther texture is linear... smooth it...
            // Scale the light cone
            AddLine(b, "lightConeHalfDepth *= volumeMaxDisplacement;");

            // Then, get the screen depth and volume depth
            AddLine(b, "float screenZ = tex2D(sys_DepthSamp, cReprojUV).a;");
            AddLine(b, "float volumeZ = (input.V_Vs.z + lightConeHalfDepth);");

            // Then, calculate the thickness
            // First, we calculate the depth difference between volume and screen...
            AddLine(b, "float deltaDepth = volumeZ - screenZ;");
            // This is the volume thickness
            AddLine(b, "float thickness = lightConeHalfDepth;");
            // If something is overlapped in the billboard volume.. the thickness is smaller..
            AddLine(b, "if (screenZ < 0) thickness = clamp(volumeZ - screenZ, 0, thickness);");

            //AddLine(b, "pipeline.Opacity *= saturate(thickness);");
            AddLine(b, "pipeline.Opacity *= volMap.r;");
            AddLine(b, "pipeline.Opacity *= thickness;");
            AddLine(b, "pipeline.Opacity = saturate(pipeline.Opacity);");
        }
    }
}
